#include "./BSP/KEY/key_manager.h"
#include "./BSP/LED/led_manager.h"
#include "stdio.h"

/* -------------------------------------------- 按键状态管理 ---------------------------------------------- */

/* 组合键状态 */
static uint8_t sg_comboState = 0;  /* 0=未激活，1=激活，2=部分释放 */

/* 按键状态定义 */
#define KEY_STATE_IDLE    0  /* 空闲状态 */
#define KEY_STATE_COMBO   1  /* 组合键激活状态 */
#define KEY_STATE_PARTIAL 2  /* 部分释放状态 */

/**
 * @brief  更新组合键状态
 * @param  sysTime 当前系统时间，单位毫秒
 */
static void UpdateComboKeyState(uint32_t sysTime)
{
    bool key0State = GPIO_GET_KEY0();
    bool key1State = GPIO_GET_KEY2();
    
    /* 快速状态处理 */
    if (key0State && key1State)
    {
        /* 两个按键同时按下，激活组合键状态 */
        sg_comboState = KEY_STATE_COMBO;
    }
    else if (!key0State && !key1State)
    {
        /* 两个按键都释放，回到空闲状态 */
        sg_comboState = KEY_STATE_IDLE;
    }
    else if (sg_comboState == KEY_STATE_COMBO)
    {
        /* 只有一个按键松开，部分释放状态 */
        sg_comboState = KEY_STATE_PARTIAL;
    }
}

/* -------------------------------------------- 按键IO初始化 ---------------------------------------------- */

static void InitKeyIo(void)
{ 
    GPIO_InitTypeDef gpio_init_struct;
    
    /* 开启时钟 */
    KEY0_GPIO_CLK_ENABLE();                                     /* KEY0时钟使能 */
    KEY1_GPIO_CLK_ENABLE();                                     /* KEY1时钟使能 */
    KEY2_GPIO_CLK_ENABLE();                                     /* KEY2时钟使能 */

    /* GPIO初始化 */
    gpio_init_struct.Pin = KEY0_GPIO_PIN;                       /* KEY0引脚 */
    gpio_init_struct.Mode = GPIO_MODE_INPUT;                    /* 输入 */
    gpio_init_struct.Pull = GPIO_PULLUP;                        /* 上拉 */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;              /* 高速 */
    HAL_GPIO_Init(KEY0_GPIO_PORT, &gpio_init_struct);           /* KEY0引脚模式设置,上拉输入 */

    gpio_init_struct.Pin = KEY1_GPIO_PIN;                       /* KEY1引脚 */
    gpio_init_struct.Mode = GPIO_MODE_INPUT;                    /* 输入 */
    gpio_init_struct.Pull = GPIO_PULLUP;                        /* 上拉 */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;              /* 高速 */
    HAL_GPIO_Init(KEY1_GPIO_PORT, &gpio_init_struct);           /* KEY1引脚模式设置,上拉输入 */

    gpio_init_struct.Pin = KEY2_GPIO_PIN;                       /* KEY2引脚 */
    gpio_init_struct.Mode = GPIO_MODE_INPUT;                    /* 输入 */
    gpio_init_struct.Pull = GPIO_PULLDOWN;                      /* 下拉 */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;              /* 高速 */
    HAL_GPIO_Init(KEY2_GPIO_PORT, &gpio_init_struct);           /* KEY2引脚模式设置,下拉输入 */
}

/* -------------------------------------------- 按键状态读取函数 ------------------------------------------- */

cotKeyState_e ReadKey0(void)
{
    /* 如果组合键处于活动状态或部分释放状态，则不触发单键 */
    if (sg_comboState != KEY_STATE_IDLE)
    {
        return COT_KEY_OFF;
    }
    
    /* 正常状态，上键读取上键的状态 */
    return (GPIO_GetKEY() == KEY_CODE_0) ? COT_KEY_ON : COT_KEY_OFF;
}

cotKeyState_e ReadKey1(void)
{
    /* 如果组合键处于活动状态或部分释放状态，则不触发单键 */
    if (sg_comboState != KEY_STATE_IDLE)
    {
        return COT_KEY_OFF;
    }

    /* 正常状态，下键读取下键的状态 */
    return (GPIO_GetKEY() == KEY_CODE_1) ? COT_KEY_ON : COT_KEY_OFF;
}

cotKeyState_e ReadKey2(void)
{
    return (GPIO_GetKEY() == KEY_CODE_2) ? COT_KEY_ON : COT_KEY_OFF;
}

/* 组合键检测函数 */
cotKeyState_e ReadKey0_1(void)
{
    /* 仅在完全按下状态时返回按下 */
    if (sg_comboState == KEY_STATE_COMBO)
    {
        return COT_KEY_ON;
    }
    return COT_KEY_OFF;
}

/* -------------------------------------------- 按键回调函数 ---------------------------------------------- */

/* KEY0键回调函数 */
static void OnKey0Press(cotKey_t key)
{ 
    /* 如果组合键处于活动状态，不处理单键事件 */
    if (sg_comboState != KEY_STATE_IDLE)
    {
        return;
    }
    
    if (!cotKey_IsLongPress(key))  /* 判断是否触发了长按 */
    {
        if (cotKey_IsTriggerWayMet(key, COT_KEY_TRIGGER_WAY_PRESS)) /* 按下首次触发 */
        {
            printf("KEY0 pressed\r\n");
        }

        if (cotKey_IsTriggerWayMet(key, COT_KEY_TRIGGER_WAY_LOSSEN)) /* 识别到短按 */
        {
            cotLed_Toggle(LED_0);
            printf("KEY0 released\r\n");
        }
    }
    else
    {
        if (cotKey_IsTriggerWayMet(key, COT_KEY_TRIGGER_WAY_PRESS)) /* 识别到长按 */
        {
            cotLed_Toggle(LED_0);
            printf("KEY0 long press detected\r\n");
        }

        if (cotKey_IsTriggerWayMet(key, COT_KEY_TRIGGER_WAY_LOSSEN)) /* 长按松开 */
        {
            printf("KEY0 long press released\r\n");  
        }
    }
}

/* KEY1键回调函数 */
static void OnKey1Press(cotKey_t key)
{
    /* 如果组合键处于活动状态，不处理单键事件 */
    if (sg_comboState != KEY_STATE_IDLE)
    {
        return;
    }

    if (!cotKey_IsLongPress(key))  /* 判断是否触发了长按 */
    {
        if (cotKey_IsTriggerWayMet(key, COT_KEY_TRIGGER_WAY_PRESS)) /* 按下首次触发 */
        {
            printf("Key1 pressed\r\n");
        }

        if (cotKey_IsTriggerWayMet(key, COT_KEY_TRIGGER_WAY_LOSSEN)) /* 识别到短按 */
        {
            cotLed_Toggle(LED_1);
            printf("Key1 released\r\n");
        }
    }
    else
    {
        if (cotKey_IsTriggerWayMet(key, COT_KEY_TRIGGER_WAY_PRESS)) /* 识别到长按 */
        {
            cotLed_Toggle(LED_1);
            printf("Key1 long press detected\r\n");            
        }

        if (cotKey_IsTriggerWayMet(key, COT_KEY_TRIGGER_WAY_LOSSEN)) /* 长按松开 */
        {
            printf("Key1 long press released\r\n");
        }
    }
}

/* KEY2键回调函数 */
static void OnKey2Press(cotKey_t key)
{
    if (!cotKey_IsLongPress(key))  /* 判断是否触发了长按 */
    {
        if (cotKey_IsTriggerWayMet(key, COT_KEY_TRIGGER_WAY_PRESS)) /* 按下首次触发 */
        {
            printf("Key2 pressed\r\n");
        }

        if (cotKey_IsTriggerWayMet(key, COT_KEY_TRIGGER_WAY_LOSSEN)) /* 识别到短按 */
        {
            cotLed_Toggle(LED_1);
            printf("Key2 released\r\n");
        }
    }
    else
    {
        if (cotKey_IsTriggerWayMet(key, COT_KEY_TRIGGER_WAY_PRESS)) /* 识别到长按 */
        {
            cotLed_Toggle(LED_1);
            printf("Key2 long press detected\r\n");
        }

        if (cotKey_IsTriggerWayMet(key, COT_KEY_TRIGGER_WAY_LOSSEN)) /* 长按松开 */
        {
            printf("Key2 long press released\r\n");
        }
    }
}

/* 组合键回调函数 */
static void OnKey0_1Press(cotKey_t key)
{
    if (!cotKey_IsLongPress(key))  /* 判断是否触发了长按 */
    {
        if (cotKey_IsTriggerWayMet(key, COT_KEY_TRIGGER_WAY_PRESS)) /* 按下首次触发 */
        {
            printf("Key0_1 combo pressed\r\n");
        }

        if (cotKey_IsTriggerWayMet(key, COT_KEY_TRIGGER_WAY_LOSSEN)) /* 识别到短按 */
        {
             cotLed_Toggle(LED_1);
             printf("Key0_1 combo released\r\n");
        }
    }
    else
    {
        if (cotKey_IsTriggerWayMet(key, COT_KEY_TRIGGER_WAY_PRESS)) /* 识别到长按 */
        {
            cotLed_Toggle(LED_1);
            printf("Key0_1 combo long press detected\r\n");
        }

        if (cotKey_IsTriggerWayMet(key, COT_KEY_TRIGGER_WAY_LOSSEN)) /* 长按松开 */
        {
            printf("Key0_1 combo long press released\r\n");
        }
    }
}

/* -------------------------------------------- 按键模块API函数 ------------------------------------------- */

/**
 * @brief  按键初始化函数
 * @param  无
 * @retval 无
 */
void FML_KEY_Init(void)
{
    static cotKeyCfg_t s_keyTable[KEY_MAX_NUM] =
    {
        {.pfnKeyState = ReadKey0},
        {.pfnKeyState = ReadKey1},
        {.pfnKeyState = ReadKey2},
        {.pfnKeyState = ReadKey0_1},
    };

    /* 初始化按键IO */
    InitKeyIo();
    
    /* 初始化组合键状态 */
    sg_comboState = KEY_STATE_IDLE;

    /* 初始化COT按键模块 */
    cotKey_Init(s_keyTable, KEY_MAX_NUM);
    
    /* 注册按键回调 */
    cotKey_Listen(KEY0, OnKey0Press);
    cotKey_Listen(KEY1, OnKey1Press);
    cotKey_Listen(KEY2, OnKey2Press);
    cotKey_Listen(KEY0_1, OnKey0_1Press);

    /* 统一配置所有按键为长按模式 */
    cotKey_ConfigLongPressMode(KEY0, 1500, 500);   /* 1.5秒长按，0.5秒重复 */
    cotKey_ConfigLongPressMode(KEY1, 1500, 500);   /* 1.5秒长按，0.5秒重复 */
    cotKey_ConfigLongPressMode(KEY2, 1500, 500);   /* 1.5秒长按，0.5秒重复 */
    cotKey_ConfigLongPressMode(KEY0_1, 1000, 500); /* 1秒长按，0.5秒重复 */
}

/**
 * @brief  按键扫描处理函数，需要周期调用
 * @param  sysTime 当前系统时间，单位毫秒
 * @retval 无
 */
void FML_KEY_Scan(uint32_t sysTime)
{
    /* 更新组合键状态 */
    UpdateComboKeyState(sysTime);
    
    /* 调用COT按键扫描函数 */
    cotKey_Scan(sysTime);
}

/**
 * @brief  获取组合键状态
 * @param  无
 * @retval 返回组合键是否处于活动状态
 */
bool FML_KEY_IsComboActive(void)
{
    return sg_comboState != KEY_STATE_IDLE;
}
